﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using DynaSpace.Entity;
using Microsoft.Xna.Framework.Graphics;

namespace DynaSpace
{
	/// <summary>
	/// Třída sloužící k vykreslení herní plochy
	/// </summary>
	public class PlayerView
	{
		private int width, height;
		private Playground p;
		private Viewport viewport;
		private bool firstInit = true;
		internal float X, Y;
		Vector2 renderPosition;
		private ScrollingSpeed scrolling;

		/// <summary>
		/// Inicializacuje novou instanci <see cref="PlayerView"/>.
		/// </summary>
		/// <param name="left">Pozice vykreslování v pixelech</param>
		/// <param name="top">Pozice vykreslování v pixelech</param>
		/// <param name="width">Šířka pohledu v pixelech</param>
		/// <param name="height">Výška pohledu v pixelech</param>
		/// <param name="followObject">Objekt, který se bude při každém updatu sledovat. Může být null.</param>
		/// <param name="scrolling">Ryhchlost scrollování</param>
		/// <param name="p">Herní plocha</param>
		public PlayerView(int left, int top, int width, int height, EntityBase followObject, Playground p, ScrollingSpeed scrolling)
		{
			this.renderPosition = new Vector2(left, top);
			this.width = width;
			this.height = height;
			this.FollowObject = followObject;
			this.p = p;
			this.scrolling = scrolling;
			InvalidateViewport();
		}

		/// <summary>
		/// Výčet rychlostí přiblížení na objekt
		/// </summary>
		public enum ScrollingSpeed
		{
			/// <summary>
			/// Pozice hráče je následována pomalu (obrazovka se netrhá)
			/// </summary>
			SlowFollow,
			/// <summary>
			/// Rychlé následování pozice hráče
			/// </summary>
			SpeedFollow,
			/// <summary>
			/// Fixní pohled na hráče
			/// </summary>
			Fixed
		}

		/// <summary>
		/// Vrací nebo nastavuje sledovaný object
		/// </summary>
		public EntityBase FollowObject { get; set; }

		/// <summary>
		/// Vrací viewport pro vykreslení tototo pohledu na hráče
		/// </summary>
		public Viewport Viewport
		{
			get
			{
				return viewport;
			}
		}

		/// <summary>
		/// Provede update pozice pohledu
		/// </summary>
		public virtual void Update(GameTime gameTime, Vector2 followPosition)
		{
			if (firstInit)
			{
				X = followPosition.X;
				Y = followPosition.Y;
				firstInit = false;
			}
			else
			{
				double mv = 1.0;
				if (scrolling != ScrollingSpeed.Fixed)
				{
					mv = Math.Min(1.0, gameTime.ElapsedGameTime.TotalMilliseconds / (scrolling == ScrollingSpeed.SlowFollow ? 200 : 100));
				}

				X = (float)(X * (1 - mv) + followPosition.X * mv);
				Y = (float)(Y * (1 - mv) + followPosition.Y * mv);
			}
		}

		/// <summary>
		/// Provede update pozice pohledu
		/// </summary>
		public virtual void Update(GameTime gameTime)
		{
			Vector2 playerPos = FollowObject == null ?
				new Vector2(0, 0) :
				FollowObject.Position + new Vector2(0.5f,0.5f);

			Update(gameTime, playerPos);
		}

		/// <summary>
		/// Vrací nebo nastavuje pozici levého horního rohu pro renderování v pixelech
		/// </summary>
		public Vector2 RenderPosition
		{
			get
			{
				return renderPosition;
			}
			set
			{
				renderPosition = value;
				InvalidateViewport();
			}
		}

		/// <summary>
		/// Vrací pozici levého horního rohu v polích aktuálního pohledu
		/// </summary>
		public Vector2 Position
		{
			get
			{
				return new Vector2(X - (float)width / EntityBase.SIZEX / 2f, Y - (float)height / EntityBase.SIZEY / 2f);
			}
		}

		/// <summary>
		/// Vykreslí obsah na spritebatch
		/// </summary>
		/// <param name="sb"><see cref="SpriteBatch"/>, na který se bude vykreslovat</param>
		public void Render(SpriteBatch sb)
		{
			sb.GraphicsDevice.Viewport = Viewport;
			sb.Begin();

			BeforeRender(sb);
			
			// vykreslit entity, které jsou vidět
			foreach (var item in p.Map.GetCloseEntities(Position.X, Position.Y, width / EntityBase.SIZEX, height / EntityBase.SIZEY))
			{
				if(item is IRendeable)
					(item as IRendeable).Render(Position, sb);
			}

			AfterRender(sb);

			sb.End();
 		}

		/// <summary>
		/// Vyvolá se před vykreslováním.
		/// SpriteBatch je již otevřený.
		/// </summary>
		/// <param name="sb"></param>
		public virtual void BeforeRender(SpriteBatch sb)
		{
		}

		/// <summary>
		/// Vyvolá se po vykreslování.
		/// SpriteBatch je stále otevřený.
		/// </summary>
		/// <param name="sb"></param>
		public virtual void AfterRender(SpriteBatch sb)
		{
		}

		private void InvalidateViewport()
		{
			viewport = new Viewport()
			{
				X = (int)RenderPosition.X,
				Y = (int)RenderPosition.Y,
				Width = (int)(width),
				Height = (int)(height)
			};
		}

	}

}
